#include "stdafx.h"
#include <tinyxml.h>
#include "EnvironmentSound.h"

const TiXmlElement* IterateChildElements(const TiXmlElement* xmlElement, const TiXmlElement* childElement)
{
    if (xmlElement != 0)
    {
        if (childElement == 0)
            childElement = xmlElement->FirstChildElement();
        else
            childElement = childElement->NextSiblingElement();
        
        return childElement;
    }

    return 0;
}

bool getBool(const String& value)
{
    String valueLower = value;
    StringUtil::toLowerCase(valueLower);
    if (valueLower == "false" || value == "no" || value == "0")
        return false;
    else
        return true;
}   

Real GetRealAttribute(const TiXmlElement* xmlElement, const char* name, Real defaultValue = 0)
{
    String value = xmlElement->Attribute(name);
    return value.empty() ? defaultValue : StringConverter::parseReal(value);    
}

int GetIntAttribute(const TiXmlElement* xmlElement, const char* name, int defaultValue = 0)
{
    String value = xmlElement->Attribute(name);
    return value.empty() ? defaultValue : StringConverter::parseInt(value);
}

Vector3 LoadXYZ(const TiXmlElement* objectElement)
{
    Vector3 xyz;
    xyz.x = GetRealAttribute(objectElement, "x");
    xyz.y = GetRealAttribute(objectElement, "y");
    xyz.z = GetRealAttribute(objectElement, "z");
    return xyz;
}

Light::LightTypes ParseLightType(const String& type)
{
    String typeLower = type;
    StringUtil::toLowerCase(typeLower);

    if (typeLower == "point")
        return Light::LT_POINT;
    else if (typeLower == "directional")
        return Light::LT_DIRECTIONAL;
    else if (typeLower == "spot")
        return Light::LT_SPOTLIGHT;

    StringUtil::StrStreamType errorMessage;
    errorMessage << "Invalid light type specified: " << type;

    OGRE_EXCEPT
        (
        Exception::ERR_INVALIDPARAMS,
	    errorMessage.str(), 
	    "OgreMaxUtilities::ParseLightType"
        );
}

Quaternion LoadRotation(const TiXmlElement* objectElement)
{
    Quaternion rotation = Quaternion::IDENTITY;

        rotation.x = GetRealAttribute(objectElement, "qx", 1);
        rotation.y = GetRealAttribute(objectElement, "qy", 0);
        rotation.z = GetRealAttribute(objectElement, "qz", 1);
        rotation.w = GetRealAttribute(objectElement, "qw", 0);
   
	return rotation;
}

ColourValue LoadColor(const TiXmlElement* objectElement)
{   
    ColourValue color;
    color.r = GetRealAttribute(objectElement, "r", 0);
    color.g = GetRealAttribute(objectElement, "g", 0);
    color.b = GetRealAttribute(objectElement, "b", 0);
    color.a = 1;
    return color;
}

String GetStringAttribute(const TiXmlElement* xmlElement, const char* name)
{
    const char* value = xmlElement->Attribute(name);
    if (value != 0)
        return value;
    else
        return StringUtil::BLANK;    
}

void LoadLightAttenuation(const TiXmlElement* objectElement, Light* light)
{
	
    String value;

    value = GetStringAttribute(objectElement, "range");
    Real range = value.empty() ? light->getAttenuationRange() : StringConverter::parseReal(value);

    value = GetStringAttribute(objectElement, "constant");
    Real constant = value.empty() ? light->getAttenuationConstant() : StringConverter::parseReal(value);

    value = GetStringAttribute(objectElement, "linear");
    Real linear = value.empty() ? light->getAttenuationLinear() : StringConverter::parseReal(value);

    value = GetStringAttribute(objectElement, "quadric");
    Real quadric = value.empty() ? light->getAttenuationQuadric() : StringConverter::parseReal(value);

    light->setAttenuation(range, constant, linear, quadric);    
}

void LoadLightRange(const TiXmlElement* objectElement, Light* light)
{

    if (light->getType() == Light::LT_SPOTLIGHT)
    {
        String value;

        value = GetStringAttribute(objectElement, "inner");
        if (!value.empty())
            light->setSpotlightInnerAngle(Radian(StringConverter::parseReal(value)));

        value = GetStringAttribute(objectElement, "outer");
        if (!value.empty())
            light->setSpotlightOuterAngle(Radian(StringConverter::parseReal(value)));

        value = GetStringAttribute(objectElement, "falloff");
        if (!value.empty())
            light->setSpotlightFalloff(StringConverter::parseReal(value));
    }
}

void GetChildText(const TiXmlElement* xmlElement, String& text)
{
    //Get the first element 
    const TiXmlNode* childNode = xmlElement->FirstChild();
    while (childNode != 0)
    {
        if (childNode->Type() == TiXmlNode::TEXT)
        {
            const TiXmlText* textNode = childNode->ToText();
            if (textNode != 0)
            {
                text = textNode->Value();
                break;
            }
        }
        childNode = xmlElement->NextSibling();
    }    
}

void loadPlane(const TiXmlElement* planeElement,SceneNode* node, Ogre::SceneManager *mSceneMgr)
{   


	Ogre::Vector3 normal;
	Ogre::Vector3 upVector;

    const TiXmlElement* childElement = 0;
    while (childElement = IterateChildElements(planeElement, childElement))
    {
	

        String elementName = childElement->Value();
      
		if (elementName == "normal")
			normal=LoadXYZ(childElement);
        else if (elementName == "upVector")
			upVector=LoadXYZ(childElement);
       
    }

	Ogre::Plane plane(normal, GetRealAttribute(planeElement, "distance"));
	MeshManager::getSingleton().createPlane
        (
        planeElement->Attribute("name"), 
		Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
        plane,
        GetRealAttribute(planeElement, "width"), GetRealAttribute(planeElement, "height"),
        GetIntAttribute(planeElement, "xSegments"), GetIntAttribute(planeElement, "ySegments"),
        getBool(planeElement->Attribute("normals")), GetIntAttribute(planeElement, "numTexCoordSets"),
        GetRealAttribute(planeElement, "uTile"), GetRealAttribute(planeElement, "vTile"),
        upVector
        );

	Ogre::Entity* ent;
	ent= mSceneMgr->createEntity( planeElement->Attribute("name"), planeElement->Attribute("name") );
	ent->getMesh()->buildTangentVectors();
	node->attachObject( ent );
	ent->setCastShadows(getBool(planeElement->Attribute("castShadows")));
	ent->setMaterialName(planeElement->Attribute("material"));
	ent->setVisibilityFlags(1);
}

void loadLight(const TiXmlElement* lightElement,SceneNode* node, Ogre::SceneManager *mSceneMgr)
{   


    //Create the light
    Light* light = mSceneMgr->createLight(lightElement->Attribute("name"));
    light->setType(ParseLightType(GetStringAttribute(lightElement, "type")));
    light->setCastShadows(getBool(lightElement->Attribute("castShadows")));
    light->setPowerScale(GetRealAttribute(lightElement, "power"));
	node->attachObject(light);

    const TiXmlElement* childElement = 0;
    while (childElement = IterateChildElements(lightElement, childElement))
    {
	

        String elementName = childElement->Value();
      
		if (elementName == "colourDiffuse")
			light->setDiffuseColour(LoadColor(childElement));
        else if (elementName == "colourSpecular")
			light->setSpecularColour(LoadColor(childElement));
        else if (elementName == "lightRange")
			LoadLightRange(childElement, light);
        else if (elementName == "lightAttenuation")
            LoadLightAttenuation(childElement, light);
        else if (elementName == "position")
            light->setPosition(LoadXYZ(childElement));
        else if (elementName == "normal")
            light->setDirection(LoadXYZ(childElement));    
    }
}

void loadEntity(const TiXmlElement* entityElement,SceneNode* node, bool visible, Ogre::SceneManager *mSceneMgr,OgreNewt::World* mWorld,EnvironmentSounds* env,OgreNewt::MaterialID* flag_mat)
{
		Ogre::Real mass = 0.5;
		Entity* ent;
		
		ent = mSceneMgr->createEntity( entityElement->Attribute("name"), entityElement->Attribute("meshFile") );
		node->attachObject( ent );
		
	ent->setVisible(visible);

	
	String str = GetStringAttribute(entityElement,"castShadows");
	if( !str.empty() && !getBool(str)) ent->setCastShadows(false); else ent->setCastShadows(true);
	
	const TiXmlElement* subentityElement=entityElement->FirstChildElement("subentities");
    const TiXmlElement* childElement = 0;
    while (childElement = IterateChildElements(subentityElement, childElement))
    {
        int index = GetIntAttribute(childElement, "index", 0);
        ent->getSubEntity(index)->setMaterialName(GetStringAttribute(childElement, "materialName"));
    }

	

	const TiXmlElement* userdataElement=entityElement->FirstChildElement("userData");

	if (userdataElement==NULL)
		ent->setVisibilityFlags(1);
	else
	{

	Ogre::String userData;
    GetChildText(userdataElement,userData);





Ogre::Log* myLog = Ogre::LogManager::getSingleton().getDefaultLog();
myLog->logMessage(userData,LML_NORMAL);

TiXmlDocument document;
document.Parse(userData.c_str());
if (!document.Error())
{
TiXmlElement *root=document.RootElement();
if (root->Value()!=NULL)
{
Ogre::String rootTag(root->Value());


if (rootTag == "PhysicalBody")
{

	const TiXmlElement* childElemen;
	const TiXmlElement* childElemens;
	childElemen=root->FirstChildElement();
	childElemens=childElemen->NextSiblingElement();
	String elementName=childElemen->GetText();
	myLog->logMessage(rootTag,LML_NORMAL);
	myLog->logMessage(elementName,LML_NORMAL);

	if (elementName=="conv")
	{
				OgreNewt::ConvexCollisionPtr col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::ConvexHull(mWorld, ent,0));
				
				// then make the rigid body.
				OgreNewt::Body* body = new OgreNewt::Body( mWorld, col );

				Ogre::Vector3 inertia, offset;
				col->calculateInertialMatrix(inertia, offset);
				#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
				//no longer need the collision shape object
				delete col;
				#endif

				myLog->logMessage("matID je:",LML_NORMAL);
				myLog->logMessage(childElemens->GetText(),LML_NORMAL);
				int mat=Ogre::StringConverter::parseInt(childElemens->GetText());

				body->setUserData(Ogre::Any(mat));
				childElemens=childElemens->NextSiblingElement();

				myLog->logMessage("mass je:",LML_NORMAL);
				myLog->logMessage(childElemens->GetText(),LML_NORMAL);
				Real mass=Ogre::StringConverter::parseReal(childElemens->GetText());
				body->setMassMatrix( mass, inertia );
				body->setType(Ogre::StringConverter::parseInt(childElemens->NextSiblingElement()->GetText()));
				if(body->getType()==2 || body->getType()==5 || body->getType()==6) body->setMaterialGroupID(flag_mat);
				body->setCenterOfMass(offset);
				//body->setContinuousCollisionMode(1);
				//body->setAngularDamping(Vector3(0,0,0));
				body->setLinearDamping(0.3);
				//body->setAutoSleep(0);
				//body->setMaterialGroupID();
				// attach to the scene node.
				body->setPositionOrientation(node->_getDerivedPosition(), node->_getDerivedOrientation() );
				body->attachNode( node );	
					
			   body->setStandardForceCallback();

	}
	if (elementName=="tree"){

		OgreNewt::CollisionPtr col = OgreNewt::CollisionPtr(new OgreNewt::CollisionPrimitives::TreeCollision( mWorld, ent, false, 0 ));
		OgreNewt::Body* bod = new OgreNewt::Body( mWorld, col );
		
		#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
		delete col;
		#endif

		int mat=Ogre::StringConverter::parseInt(childElemens->GetText());
		bod->setUserData(Ogre::Any(mat));
		bod->setPositionOrientation( node->_getDerivedPosition(), node->_getDerivedOrientation() );
		bod->attachNode( node );
		bod->setType(Ogre::StringConverter::parseInt(childElemens->NextSiblingElement()->GetText()));

	}
}
else
if(rootTag == "EnvSoundBody")
{
	
	const TiXmlElement* childElement;
	childElement=root->FirstChildElement();
	float volume=Ogre::StringConverter::parseReal(childElement->GetText());
	childElement=childElement->NextSiblingElement();
	bool cont=Ogre::StringConverter::parseBool(childElement->GetText());
	childElement=childElement->NextSiblingElement();
	float decay=Ogre::StringConverter::parseReal(childElement->GetText());
	childElement=childElement->NextSiblingElement();
	Ogre::String sound="../../media/"+Ogre::String(childElement->GetText());
	Vector3 scale=node->getScale();
	node->setScale(1,1,1);
	Ogre::Matrix4 trans=node->_getFullTransform().inverse();

	env->addSound(trans,scale,decay,volume,sound,cont);

	node->detachAllObjects();
	mSceneMgr->destroySceneNode(node);
	myLog->logMessage(rootTag+"-"+sound,LML_NORMAL);
}

}}
}

		

		

}

void loadNode(const TiXmlElement* nodeElement, Ogre::SceneManager *mSceneMgr,OgreNewt::World* mWorld,EnvironmentSounds* env,OgreNewt::MaterialID* flag_mat)
{

	/*Ogre::Vector3 position(0,0,0);
	Ogre::Vector3 scale(1,1,1);
	Ogre::Quaternion rotation(0,0,0,1);
	Ogre::Entity* ent=NULL;*/
	SceneNode* node;
	Ogre::String name;
		name = nodeElement->Attribute("name");

		node = mSceneMgr->getRootSceneNode()->createChildSceneNode( name );

		
	bool visible=true;
	if(nodeElement->Attribute("visibility")!=NULL){
			Ogre::String v=nodeElement->Attribute("visibility");
			if (v=="hidden") visible=false; }
	

	 String elementName;
    const TiXmlElement* childElement = 0;
    while (childElement = IterateChildElements(nodeElement, childElement))
    {
        elementName = childElement->Value();
        
        if (elementName == "position")
            node->setPosition(LoadXYZ(childElement));
        else if (elementName == "rotation")
            node->setOrientation(LoadRotation(childElement));
        else if (elementName == "scale")
            node->setScale(LoadXYZ(childElement));
        else if (elementName == "entity")
            loadEntity(childElement, node,visible,mSceneMgr,mWorld,env,flag_mat);
        else if (elementName == "light")
            loadLight(childElement, node,mSceneMgr);
		else if (elementName == "plane")
            loadPlane(childElement, node,mSceneMgr);
    }

}

void loadScene(Ogre::String filename, Ogre::SceneManager *mSceneMgr,OgreNewt::World* m_World,EnvironmentSounds* env,OgreNewt::MaterialID* flag_mat)
{
	TiXmlDocument document;
	document.LoadFile(filename.c_str());
	const TiXmlElement* mainElement = document.RootElement();
	const TiXmlElement* nodesElement = mainElement->FirstChildElement("nodes");



	 String elementName;
    const TiXmlElement* childElement = 0;
    while (childElement = IterateChildElements(nodesElement, childElement))
    {
        elementName = childElement->Value();
        
        if (elementName == "node")
            loadNode(childElement,mSceneMgr,m_World,env,flag_mat);
        /*else if (elementName == "skyBox")
            LoadSkyBox(childElement);*/
    }
}